#include "C3DModel.h"

C3DModel::C3DModel(void)
{
	m_triSize = 0;
	m_triArray = NULL;
	m_texOwnsMemory=false;
	m_texArray = NULL;
	m_texSize = 0;
}

C3DModel::~C3DModel(void)
{
	Clear();
}

void C3DModel::Create( int size )
{
	m_triSize = size;
	m_triArray = new C3DTriangle[m_triSize];
}

void C3DModel::SetTriangle( int index,const C3DTriangle& triangle )
{
	if(index<0 || index>=m_triSize)
		return;

	m_triArray[index]=triangle;
}

void C3DModel::Clear()
{
	if(m_triArray!=NULL)
		delete [] m_triArray;
	m_triArray = NULL;
	m_triSize = 0;

	if(m_texOwnsMemory)
		if(m_texArray!=NULL)
			delete [] m_texArray;
	
	m_texArray = NULL;
	m_texSize = 0;
	m_texOwnsMemory = false;
}

void C3DModel::Draw()
{
	glPushMatrix();
	glTranslatef(m_position.m_x,m_position.m_y,m_position.m_z);

	if(m_texArray!=NULL)
		glEnable( GL_TEXTURE_2D );
	glBegin(GL_TRIANGLES);
	int curtex = -1;

	GLfloat tcoord1[2] = {0,0};
	GLfloat tcoord2[2] = {0,0};
	GLfloat tcoord3[2] = {0,0};

	for(int i=0;i<m_triSize;i++)
	{
		// in the future this code should be optimized
		if(m_texArray!=NULL)
		{
			if(curtex!=m_triArray[i].m_texIndex)
			{
				curtex = m_triArray[i].m_texIndex;
				glEnd();
				m_texArray[curtex].Bind();
				glBegin(GL_TRIANGLES);
			}
			tcoord1[0] = m_triArray[i].m_point[0].m_u;
			tcoord1[1] = m_triArray[i].m_point[0].m_v;

			tcoord2[0] = m_triArray[i].m_point[1].m_u;
			tcoord2[1] = m_triArray[i].m_point[1].m_v;

			tcoord3[0] = m_triArray[i].m_point[2].m_u;
			tcoord3[1] = m_triArray[i].m_point[2].m_v;
		}
		glNormal3f(m_triArray[i].m_normal.m_x,m_triArray[i].m_normal.m_y,m_triArray[i].m_normal.m_z);

		glTexCoord2f(tcoord1[0],  tcoord1[1]);
		glVertex3f(m_triArray[i].m_point[0].m_x, m_triArray[i].m_point[0].m_y, m_triArray[i].m_point[0].m_z); 
		glTexCoord2f(tcoord2[0],  tcoord2[1]);
		glVertex3f(m_triArray[i].m_point[1].m_x, m_triArray[i].m_point[1].m_y, m_triArray[i].m_point[1].m_z); 
		glTexCoord2f(tcoord3[0],  tcoord3[1]);
		glVertex3f(m_triArray[i].m_point[2].m_x, m_triArray[i].m_point[2].m_y, m_triArray[i].m_point[2].m_z);
		
	}
	
	
	glEnd();

	if(m_texArray!=NULL)
		glDisable( GL_TEXTURE_2D );

	C3DObject::Draw();
	glPopMatrix();
}

bool C3DModel::LoadModel( char* filename )
{
	if(filename==NULL)
		return false;

	Lib3dsFile* model =  lib3ds_file_open(filename);
	if(model==NULL)
		return false;

	
	m_texSize = model->nmaterials;
	m_texArray = new C3DTexture[m_texSize];
	m_texOwnsMemory = true;
	for(int i=0;i<m_texSize;i++)
	{
		m_texArray[i].LoadTexture(model->materials[i]->texture1_map.name);
	}
	
	int faces = 0;
	// Loop through every mesh
	for(int i=0;i<model->nmeshes;i++)
	{
		Lib3dsMesh* mesh = model->meshes[i];
		C3DModel* submodel = new C3DModel();
		submodel->m_name = mesh->name;
		
		submodel->Create(mesh->nfaces);
		submodel->m_texOwnsMemory = false;
		submodel->m_texArray = m_texArray;
		submodel->m_texSize = m_texSize;

		for(int j=0;j<mesh->nfaces;j++)
		{
			Lib3dsFace face = mesh->faces[j];
			
			float* v0=mesh->vertices[face.index[0]];
			float* v1=mesh->vertices[face.index[1]];
			float* v2=mesh->vertices[face.index[2]];
			float* t0=mesh->texcos[face.index[0]];
			float* t1=mesh->texcos[face.index[1]];
			float* t2=mesh->texcos[face.index[2]];
			
			submodel->SetTriangle(j,C3DTriangle(
				C3DPoint(v0[0],v0[1],v0[2],t0[0],t0[1]),
				C3DPoint(v1[0],v1[1],v1[2],t1[0],t1[1]),
				C3DPoint(v2[0],v2[1],v2[2],t2[0],t2[1])));

			submodel->m_triArray[j].m_texIndex = face.material;

		}

		submodel->CalculateNormals();
		AddObject(submodel);
		
	}
	lib3ds_file_free(model);
	return true;
}

void C3DModel::CalculateNormals()
{
	for(int i=0;i<m_triSize;i++)
		m_triArray[i].CalculateNormal();
}